// ========== Copyright Header Begin ==========================================
// 
// OpenSPARC T1 Processor File: cpu_exec3.cc
// Copyright (c) 2006 Sun Microsystems, Inc.  All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
// 
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
// 
// The above named program is distributed in the hope that it will be 
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
// 
// ========== Copyright Header End ============================================
#include "bcore/InstructionEmulator.h"
#include "bcore/cpu_exec3.h"
#include "InstructionWord.h"
#include "AsiDispatchPacket.h"
#include "MemoryTransaction.h"
#include "Util/NumericUtils.h"
#include "Util/StringUtils.h"
#include "V9/V9_Asi.h"
#include "Gm/Gm_Asi.h"
#include "Sf/Sf_Asi.h"
#include "Sf/Sf_Trap.h"
#include "Sf/Sf_Mmu.h"
#include "Blaze_CBInterface.h"
#include <memory>
#include <cassert>

/* This routine executes a OP 1 instruction (CALL). */

using namespace std;
using namespace Riesling;

BlazeCBInterface::BlazeIOInterceptCB BlazeCBInterface::blazeiointerceptcb_ = NULL;

#define STORE( size, bl ) assert( 0 )

#define GET_IU_RS2( rf, instr ) (instr.i() ? instr.simm13() : rf->get(instr.rs2()))

#define GET_R1_R2( iword, r1_val, r2_val )\
    r1_val = ireg_->get( iword.rs1() );\
    r2_val = GET_IU_RS2( ireg_, iw )

#define GET_IU_EA( iword ) (ireg_->get(iword.rs1()) + GET_IU_RS2( ireg_, iw ))

#define U(foo) InstructionEmulator::unknown_instr


/*
 * The instruction OP field indexes this array and selects the exec routine.
 * The most frequent executed LD/ST operations like LDUW for example
 * are executed directly and don't have corresponding node
 * in the table below - just "unknown_fcpu_op3_instr"
 */

void (InstructionEmulator::*InstructionEmulator::exec_op3_routines[])( InstructionWord& ) = {

	       /* Col 0 (0x00 - 0x0f) */
                U(memop_err), U(memop_err), U(memop_err), &InstructionEmulator::exec_LDD,
                U(memop_err), U(memop_err), U(memop_err), &InstructionEmulator::exec_std,
                U(memop_err), U(memop_err), U(memop_err), U(memop_err),
                U(unknown_fcpu_op3_instr), U(memop_err), U(memop_err), &InstructionEmulator::exec_swapd,
                /* Col 1 (0x10 - 0x1f) */
                U(unknown_fcpu_op3_instr) , U(unknown_fcpu_op3_instr),
		U(unknown_fcpu_op3_instr), &InstructionEmulator::exec_LDD,
                U(unknown_fcpu_op3_instr), U(unknown_fcpu_op3_instr),
        	U(unknown_fcpu_op3_instr), &InstructionEmulator::exec_stda,
		U(unknown_fcpu_op3_instr), U(unknown_fcpu_op3_instr),
		U(unknown_fcpu_op3_instr), U(unknown_fcpu_op3_instr),
	        U(unknown_fcpu_op3_instr), U(memop_err), 
                U(unknown_fcpu_op3_instr), &InstructionEmulator::exec_swapa,
		/* Col 2 (0x20 - 0x2f) */
		U(memop_err), &InstructionEmulator::exec_ld_st_fsr, &InstructionEmulator::exec_ldqf, U(memop_err),
		U(memop_err), &InstructionEmulator::exec_ld_st_fsr, &InstructionEmulator::exec_stqf, U(memop_err),
		U(unknown_fcpu_op3_instr), U(unknown_fcpu_op3_instr),
		U(unknown_fcpu_op3_instr), U(unknown_fcpu_op3_instr),
		U(unknown_fcpu_op3_instr), &InstructionEmulator::exec_prefetch, U(unknown_fcpu_op3_instr),
		U(unknown_fcpu_op3_instr),
		/* Col 3 (0x30 - 0x3f) */
                U(memop_err),  U(unknown_fcpu_op3_instr), &InstructionEmulator::exec_ldqfa, U(memop_err),
		U(memop_err),  U(unknown_fcpu_op3_instr), &InstructionEmulator::exec_stqfa,	U(memop_err),
                U(unknown_fcpu_op3_instr), U(unknown_fcpu_op3_instr),
                U(unknown_fcpu_op3_instr), U(unknown_fcpu_op3_instr), 
		//                exec_casa, exec_prefetcha,
                &InstructionEmulator::exec_cas, &InstructionEmulator::exec_prefetcha,
                //exec_casxa, U(unknown_fcpu_op3_instr)
                &InstructionEmulator::exec_cas, U(unknown_fcpu_op3_instr)
};

//////////////////////////////////////////////////////





//////////////////////////////////////////////////////

AsiT InstructionEmulator::getDefaultInstrAsi()
{
    return tl_->getTL() > 0 ? V9_Asi::ASI_NUCLEUS : V9_Asi::ASI_PRIMARY;
}


//////////////////////////////////////////////////////

AsiT InstructionEmulator::getDefaultDataAsi()
{
    AsiT asi;

    if( tl_->getTL() > 0 ){
	asi = pstate_->getCLE() ? V9_Asi::ASI_NUCLEUS_LITTLE : V9_Asi::ASI_NUCLEUS;
    } else {
	asi = pstate_->getCLE() ? V9_Asi::ASI_PRIMARY_LITTLE : V9_Asi::ASI_PRIMARY;
    }

    PRINT_DEBUG( "Default data asi is 0x%x", asi );

    return asi;
}

//////////////////////////////////////////////////////

/* 
 * This routine executes load/store "complex" operation
 */
bool 
InstructionEmulator::exec_op3( InstructionWord &iw )
{
	(this->*exec_op3_routines[iw.op3()])( iw );
	return true;
}

//////////////////////////////////////////////////////

int InstructionEmulator::getPriv()
{
    return pstate_->getPRIV();
}

//////////////////////////////////////////////////////

MemoryTransaction* InstructionEmulator::getMemXact( VaddrT addr, AsiT asi )
{
    return new MemoryTransaction(addr,asi);
}

//////////////////////////////////////////////////////

PaddrT InstructionEmulator::translate( VaddrT addr, AsiT asi )
{
    auto_ptr<MemoryTransaction> mt( getMemXact( addr, asi ) );
    mmu_->translate( *mt );
    return mt->paddr();
}

//////////////////////////////////////////////////////

PaddrT InstructionEmulator::translate( MemoryTransaction &mt )
{
    mmu_->translate( mt );
    return mt.paddr();
}

//////////////////////////////////////////////////////

bool InstructionEmulator::isXlateAsi( AsiT asi )
{
    // TODO This should be changed back to Spitfire someday
    return getAsiInstance()->translate( asi );
}

//////////////////////////////////////////////////////

AsiObject *InstructionEmulator::getAsiInstance()
{
    return Gm_Asi::getInstance();
}

//////////////////////////////////////////////////////

uint64_t InstructionEmulator::readUnsigned( VaddrT vaddr, uint_t size, const InstructionWord &iw )
{
    assert(size == 1 || size == 2 || size == 4 || size == 8);
    uint64_t result = 0;
    MemoryTransaction xact( vaddr, getDefaultDataAsi(), iw, MemoryTransaction::READ, getStrand() );
    xact.size( size );
    mmu_->handleData( xact );
    addressSpace_->access( xact );
    result = xact.getData();
    return result;
}

//////////////////////////////////////////////////////

uint64_t InstructionEmulator::readSigned( VaddrT vaddr, uint_t size, const InstructionWord &iw )
{
    MemoryTransaction t( vaddr, getDefaultDataAsi(), iw, MemoryTransaction::READ, getStrand() );
    return readSigned( t, size );
}

//////////////////////////////////////////////////////

void InstructionEmulator::asiDispWrite( AsiT asi, VaddrT vaddr, uint64_t value, const InstructionWord &iw, bool internal )
{
    // Dispatch to the asi handler.	
    AsiDispatchPacket p( asi, vaddr );
    p.setData( value );
    p.setInstruction( iw );
    p.setAsiObject( getAsiInstance() );
    asiDispatcher_->write( p, (AsiDispatcher::AsiPrivT)getPriv() );
    AsiDispatchPacket::ResponseT result = p.getResponse();
    if( !p.isRespCodeSet( AsiDispatchPacket::OK ) ){
	int trapType, faultType;

	faultType = 0;
	trapType = 0;
	if( p.isRespCodeSet( AsiDispatchPacket::NOT_MAPPED ) ){
	    trapType  = Sf_Trap::data_access_exception;
	    faultType = Sf_Mmu::ILLEGAL_INSTR_VA_ASI;
	} else if( p.isRespCodeSet( AsiDispatchPacket::MEM_ADDRESS_NOT_ALIGNED ) ) {  // priority 10 
	    trapType  = Sf_Trap::mem_address_not_aligned;
	    faultType = 0;
	} else if( p.isRespCodeSet( AsiDispatchPacket::STDF_MEM_ADDRESS_NOT_ALIGNED ) ){          // priority 10 
	    trapType  = Sf_Trap::STDF_mem_address_not_aligned;
	    faultType = 0;
	} else if( p.isRespCodeSet( AsiDispatchPacket::PRIV_EXCEPTION ) ){     // priority 11
	    trapType  = Sf_Trap::privileged_action;
	    faultType = 0;
	} else if( p.isRespCodeSet( AsiDispatchPacket::INVALID_OPCODE ) ||
		   p.isRespCodeSet( AsiDispatchPacket::INVALID_ACCESS ) ){     // priority 12
	    trapType  = Sf_Trap::data_access_exception;
	    faultType = Sf_Mmu::ILLEGAL_INSTR_VA_ASI;
	} else {
	    cerr << AsiDispatchPacket::response2String( p.getResponse() ) << endl;
	    RIESLING_THROW_DOMAIN_ERROR( string("Unhandled ASI\n").append(asiDispatcher_->toString()) );
	}
	MemoryTransaction xact( vaddr, asi, iw, MemoryTransaction::WRITE, getStrand() );
	xact.size( 8 );
	xact.setData( value );
	mmu_->dMmuTrap( xact, trapType, faultType, NULL );
    }    
}

//////////////////////////////////////////////////////

uint64_t InstructionEmulator::asiDispRead( AsiT asi, VaddrT vaddr, const InstructionWord &iw, bool internal )
{

    // Dispatch to the asi handler.	
    AsiDispatchPacket p( asi, vaddr );
    p.setInstruction( iw );
    p.setAsiObject( getAsiInstance() );
    asiDispatcher_->read( p, (AsiDispatcher::AsiPrivT)getPriv() );
    AsiDispatchPacket::ResponseT result = p.getResponse();
    if( !p.isRespCodeSet( AsiDispatchPacket::OK ) ){
	int trapType, faultType;

	faultType = 0;
	trapType = 0;
	if( p.isRespCodeSet( AsiDispatchPacket::NOT_MAPPED ) ){  
	    // Although this trap is has a lower priority (12), we check this first, as
	    // the other traps depend on the <asi,vaddr> tuple being mapped
	    trapType  = Sf_Trap::data_access_exception;
	    faultType = Sf_Mmu::ILLEGAL_INSTR_VA_ASI;
	} else if( p.isRespCodeSet( AsiDispatchPacket::MEM_ADDRESS_NOT_ALIGNED ) ) {  // priority 10 
	    trapType  = Sf_Trap::mem_address_not_aligned;
	    faultType = 0;
	} else if( p.isRespCodeSet( AsiDispatchPacket::LDDF_MEM_ADDRESS_NOT_ALIGNED ) ){          // priority 10 
	    trapType  = Sf_Trap::LDDF_mem_address_not_aligned;
	    faultType = 0;
	} else if( p.isRespCodeSet( AsiDispatchPacket::PRIV_EXCEPTION ) ){     // priority 11
	    trapType  = Sf_Trap::privileged_action;
	    faultType = 0;
	} else if( p.isRespCodeSet( AsiDispatchPacket::INVALID_OPCODE ) ||
		   p.isRespCodeSet( AsiDispatchPacket::INVALID_ACCESS ) ){     // priority 12
	    trapType  = Sf_Trap::data_access_exception;
	    faultType = Sf_Mmu::ILLEGAL_INSTR_VA_ASI;
	} else {
	    cerr << AsiDispatchPacket::response2String( p.getResponse() ) << endl;
	    RS_DOMAIN_ERR( "Unandled asi. asi=0x%x, vaddr=0x%x", asi, vaddr );
	    //RIESLING_THROW_DOMAIN_ERROR( string("Unhandled ASI\n").append(asiDispatcher_->toString()) );
	}

	MemoryTransaction xact( vaddr, asi, iw, MemoryTransaction::READ, getStrand() );
	xact.size( 8 );

	// TODO check for NULL!!!!
	mmu_->dMmuTrap( xact, trapType, faultType, NULL );

	cerr << AsiDispatchPacket::response2String( p.getResponse() ) << endl;
	RIESLING_THROW_DOMAIN_ERROR( string("Unhandled ASI\n").append(asiDispatcher_->toString()) );
    }
    return p.getData();
}

//////////////////////////////////////////////////////

uint64_t InstructionEmulator::readUnsignedMemory( MemoryTransaction &xact, uint_t size )
{
    assert(size == 1 || size == 2 || size == 4 || size == 8);
    uint64_t result;
    xact.size( size );
    mmu_->handleData( xact );
    addressSpace_->access( xact );
    result = xact.getData();
    return result;
}

//////////////////////////////////////////////////////

uint64_t InstructionEmulator::readUnsigned( MemoryTransaction &xact, uint_t size )
{
    assert(size == 1 || size == 2 || size == 4 || size == 8);
    uint64_t result;
    xact.size( size );
    mmu_->handleData( xact );
    addressSpace_->access( xact );
    result = xact.getData();
    return result;
}

//////////////////////////////////////////////////////

uint64_t InstructionEmulator::readSigned( MemoryTransaction &xact, uint_t size )
{
    assert(size == 1 || size == 2 || size == 4 || size == 8);
    uint64_t result;
    xact.size( size );
    mmu_->handleData( xact );
    addressSpace_->access( xact );
    result = xact.getData();
    NumericUtils::signExtend64( result, 8 * size - 1 );
    return result;
}

//////////////////////////////////////////////////////

void InstructionEmulator::write( VaddrT vaddr, uint_t size, InstructionWord iw, uint64_t data )
{
    assert(size == 1 || size == 2 || size == 4 || size == 8);

    // DV wants to comment it out -- why is it here?
    if (BlazeCBInterface::getblazeiointerceptcb()) {
      if ((*BlazeCBInterface::getblazeiointerceptcb())(getStrand()->getId(),
						       vaddr, data, size))
	return;
    }
    

    MemoryTransaction xact( vaddr, getDefaultDataAsi(), iw, MemoryTransaction::WRITE, getStrand() );
    xact.size( size );
    xact.setData( data );
    xact.access( MemoryTransaction::WRITE );
    mmu_->handleData( xact );
    addressSpace_->access( xact );
}

//////////////////////////////////////////////////////

void InstructionEmulator::write( MemoryTransaction &xact, uint_t size )
{
    assert(size == 1 || size == 2 || size == 4 || size == 8);
    xact.size( size );    
    // xact.access( MemoryTransaction::WRITE );
    mmu_->handleData( xact );
    addressSpace_->access( xact );
}

//////////////////////////////////////////////
//
// load ASI operation - covers all ASI related cases 
// except LDDA (?) and LDFA
//
void InstructionEmulator::exec_LOAD_ASI( InstructionWord &i, VaddrT addr )
{
    uint8_t asi = i.i() ? asi_->getNative() : i.immAsi();
    uint8_t rd = i.rd();
    uint64_t paddr;
    uint64_t data, regValue;
    uint32_t op3 = i.op3();

    if( isXlateAsi( asi ) ){
	MemoryTransaction xact( addr, asi, i, MemoryTransaction::READ, getStrand() );

	switch (op3) {
	    case T3o3_lduba:
		regValue = readUnsigned( xact, 1 );
		break;
	    case T3o3_ldsba:
		regValue = readSigned( xact, 1 );
		break;
	    case T3o3_lduha:
		regValue = readUnsigned( xact, 2 );
		break;
	    case T3o3_ldsha:
		regValue = readSigned( xact, 2 );
		break;
	    case T3o3_lduwa:
		regValue = readUnsigned( xact, 4 );
		break;
	    case T3o3_ldswa:
		regValue = readSigned( xact, 4 );
		break;
	    case T3o3_ldxa:
		regValue = readUnsigned( xact, 8 );
		break;
	}

	// checkTrapBeforeCommit(i);
    
	if (rd != 0) {
	    ireg_->set( rd, regValue );
	}

    } else {
	regValue = asiDispRead( asi, addr, i );
	// checkTrapBeforeCommit(i);
	if ( rd != 0 ) {
	    ireg_->set( rd, regValue );
	}
    }
}

//////////////////////////////////////////////

void InstructionEmulator::exec_STORE_ASI( InstructionWord &i, VaddrT addr )
{
    AsiT asi = i.i() ? asi_->getNative() : i.immAsi();
    uint8_t  rd  = i.rd();
    uint32_t op3 = i.op3();
    uint64_t data;

    if ( isXlateAsi( asi ) ) {

	MemoryTransaction xact( addr, asi, i, MemoryTransaction::WRITE, getStrand() );
	xact.setData( ireg_->get( rd ) );

	// checkTrapBeforeCommit(i);

	switch (op3) {
	    case T3o3_stba:
		write( xact, 1 );
		break;
	    case T3o3_stha:
		write( xact, 2 );
		break;
	    case T3o3_stwa:
		write( xact, 4 );
		break;
	    case T3o3_stxa:
		write( xact, 8 );
		break;
	}
    } else {
	// checkTrapBeforeCommit(i);
	asiDispWrite( asi, addr, ireg_->get( rd ), i );
    }
}

//////////////////////////////////////////////

void InstructionEmulator::exec_std( InstructionWord &iw)
{
	uint64_t   ea;		/* effective address */
	uint32_t   rd  = iw.rd();
	uint64_t   lvalue;

	ea = GET_IU_EA( iw );
// 	if (rd & 0x1) {
// 	    RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 	}

	lvalue = (ireg_->get( rd ) << 32) | ((ireg_->get( rd + 1 ) & 0x0ffffffffULL));
        // checkTrapBeforeCommit(iw);
	write( ea, 8, iw, lvalue );
}

///////////////////////////////////////////////////

void 
InstructionEmulator::exec_swapd( InstructionWord &iw )
{
	uint64_t   ea;

	ea = GET_IU_EA( iw );
	exec_swap( getDefaultDataAsi(), ea, iw.rd(), iw);
}

///////////////////////////////////////////////////
// TODO define these in some other file
#define LDDA 0x13

void InstructionEmulator::exec_LDD( InstructionWord &iw )
{
        uint32_t op3  = iw.op3();
	uint32_t rd   = iw.rd();
        uint64_t addr = GET_IU_EA(iw);

	uint8_t asi;
	if( op3 == T3o3_ldda ){
	    asi = iw.i() ? asi_->getNative() : iw.immAsi();
	} else {
	    // TODO this behavior needs be made configurable
// 	    if( iw.i() == 0 && NumericUtils::getBits( iw.getNative(), 12, 5 ) != 0 ){
// 		RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 	    }
	    asi = getDefaultDataAsi();
	}

// 	if (rd & 0x1) {
// 	    RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 	}

	if ( !isXlateAsi( asi ) ) {
	    uint64_t data = asiDispRead( asi, addr, iw );
	    // checkTrapBeforeCommit(iw);
	    if (rd != 0) {
		ireg_->set( rd,     NumericUtils::getHiWord( data ) );
	    }
	    ireg_->set( rd + 1, NumericUtils::getLoWord( data ) );
	    return; 
	}

	MemoryTransaction xact( addr, asi, iw, MemoryTransaction::READ, getStrand() );
	if ( (asi == Sf_Asi::ASI_NUCLEUS_QUAD_LDD) || (asi == Sf_Asi::ASI_NUCLEUS_QUAD_LDD_LITTLE) ) {

            xact.size( 16 );
	    mmu_->handleData( xact );
	    xact.size( 8 );
	    PaddrT paddr = xact.paddr();
            
	    addressSpace_->access( xact );
	    uint64_t reg_val = xact.getData(0,false);

	    // checkTrapBeforeCommit(iw);

	    if ( rd != 0 ) {
		ireg_->set( rd,  reg_val );
	    }

	    xact.vaddr( xact.vaddr() + 8 );   // ensure va/pa stay in sync
	    xact.paddr( xact.paddr() + 8 );
	    addressSpace_->access( xact );
	    reg_val = xact.getData(0,false);
	    ireg_->set( rd + 1, reg_val );

            
	} else {

	    // The word at the effective memory address is copied into the even
	    // r register.  The word at the effective memory address + 4 is copied
	    // into the following odd-numbered r register.

	    uint64_t reg_val = readUnsigned( xact, 8 );
            
	    // checkTrapBeforeCommit(iw);

	    if (rd != 0) {
		ireg_->set( rd,     NumericUtils::getHiWord( reg_val ) );
	    }
	    ireg_->set( rd + 1, NumericUtils::getLoWord( reg_val ) );
	}
	return;
}

///////////////////////////////////////////////////

void InstructionEmulator::exec_stda( InstructionWord &iw )
{
        uint32_t op3  = iw.op3();
	uint32_t rd   = iw.rd();
        uint64_t addr = GET_IU_EA(iw);
	uint8_t asi = (iw.i() ? asi_->getNative() : iw.immAsi());
	uint64_t data = 0;
	
// 	if (rd & 0x1) {
// 	    RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 	}

	NumericUtils::setHiWord( data , ireg_->get( rd ) );
	NumericUtils::setLoWord( data , ireg_->get( rd + 1 ) );

        // checkTrapBeforeCommit(iw);

	if ( !isXlateAsi( asi ) ) {

	    asiDispWrite( asi, addr, data, iw );
	    return; 
	}

	// The lower word in even r register is copied into the word at the effective 
	// memory address. The lower word in odd-numbered r register is copied into the 
	// word at the effective memory address + 4.

	MemoryTransaction writeXact( addr, asi, iw, MemoryTransaction::WRITE, getStrand() );

	writeXact.setData( data );
	write( writeXact, 8 );

	return;
}


void InstructionEmulator::exec_swapa( InstructionWord &iw )
{
	uint64_t ea;		
	uint32_t op3 = iw.op3();
	uint32_t rd = iw.rd();
	uint32_t asi;

	ea = GET_IU_EA( iw );
	asi = iw.i() ? asi_->getNative() : iw.immAsi();
	exec_swap( asi, ea, rd, iw);
}


#define FSR_VER_FTT_QNE_MASK    0x000FE000ULL

void InstructionEmulator::exec_ld_st_fsr( InstructionWord &iw )
{

    // TODO this instruction should wait for all fp instructions
    // to finish prior to loading or storing a value.  This will
    // be an issue when we are queueing loads for Gm

    uint32_t op3  = iw.op3();
    uint32_t rd   = iw.rd();
    uint64_t addr = GET_IU_EA(iw);

//     if (rd > 1){
// 	RIESLING_TRAP( Sf_Trap::illegal_instruction );
//     }

    if ( !fpuEnabled() ){
	RIESLING_TRAP( Sf_Trap::fp_disabled );
    } 									


    if (op3 == T3o3_ldfsr) {
	if (rd == 0) {
	    // if rd is zero, this is an LDFSR, which write writes
	    // only the lower half of the FSR
	    uint64_t data = readUnsigned( addr, 4, iw );
	    uint64_t fsrTmp = fsr_->getNative();
	    data &= ~FSR_VER_FTT_QNE_MASK;
	    data |= ( fsrTmp & FSR_VER_FTT_QNE_MASK );
	    NumericUtils::setLoWord( fsrTmp, data );
	    // checkTrapBeforeCommit(iw);
	    fsr_->setNative( fsrTmp );
	} else {
	    // otherwise, this is an LDXFSR, which writes the whole FSR

	    uint64_t fsrTmp = fsr_->getNative();
	    uint64_t data   = readUnsigned( addr, 8, iw );
	    data &= ~FSR_VER_FTT_QNE_MASK;
	    data |= ( fsrTmp & FSR_VER_FTT_QNE_MASK );
	    // checkTrapBeforeCommit(iw);
	    fsr_->setNative( data );
	}
    } else {
	// checkTrapBeforeCommit(iw);
	if (rd == 0) {
	    write( addr, 4, iw, NumericUtils::getLoWord( fsr_->getNative() ) );
	} else {
	    write( addr, 8, iw, fsr_->getNative() );
	}
	fsr_->setFTT( 0 );
    }
}

void InstructionEmulator::exec_ldqf( InstructionWord &iw )
{
//     RIESLING_TRAP( Sf_Trap::illegal_instruction );
}

//
// LOAD FLOAT (4, 8 bytes) ASI operation
//
void InstructionEmulator::exec_LDF_ASI ( InstructionWord &iw, VaddrT addr )
{
    uint64_t   memValue = 0;
    uint32_t op3 = iw.op3();
    uint32_t rd  = iw.rd();
    AsiT asi = iw.i() ? asi_->getNative() : iw.immAsi();

    if( op3 == T3o3_lddfa ){
	rd = InstructionWord::decodeDoubleReg( rd );
    }

    if( getAsiInstance()->isBlockOp( asi ) == false ){
	if ( !fpuEnabled() ){
	    if ( setFpDirtyBitsWhenFpDisabled() ) {
		// checkTrapBeforeCommit(iw);
		setFpDirtyBits( rd );  // Dirty bits are set pessimistically before fp_disabled trap
	    }
	    RIESLING_TRAP( Sf_Trap::fp_disabled );
	} 									
    }

    if( !isXlateAsi( asi ) ){
        // checkTrapBeforeCommit(iw);
	freg_->setDpfp( rd, asiDispRead( asi, addr, iw ) );
	setFpDirtyBits( rd );  // TODO reorg code
	return;
    }

    if( getAsiInstance()->isBlockOp( asi ) ){
	// Block load handling
	handleBlockOp( iw, addr, asi, MemoryTransaction::READ, rd );
    } else if( getAsiInstance()->isFLdSt( asi ) ){


	MemoryTransaction readXact( addr, asi, iw, MemoryTransaction::READ, getStrand() );

        switch (asi) {
	    case Sf_Asi::ASI_FL8_PRIMARY:
	    case Sf_Asi::ASI_FL8_SECONDARY:
	    case Sf_Asi::ASI_FL8_PRIMARY_LITTLE:
	    case Sf_Asi::ASI_FL8_SECONDARY_LITTLE:
	    {
		memValue = readUnsignedMemory( readXact, 1 ) & 0x00FF;
		// checkTrapBeforeCommit(iw);
		freg_->setDpfp( rd, memValue );
		break;
	    }

	    case Sf_Asi::ASI_FL16_PRIMARY:
	    case Sf_Asi::ASI_FL16_SECONDARY:
	    case Sf_Asi::ASI_FL16_PRIMARY_LITTLE:
	    case Sf_Asi::ASI_FL16_SECONDARY_LITTLE:
	    {
		memValue = readUnsignedMemory( readXact, 2 ) & 0x00FFFF;
		// checkTrapBeforeCommit(iw);
		freg_->setDpfp( rd, memValue );
		break;
	    }

	    case Sf_Asi::ASI_PST8_PRIMARY:
	    case Sf_Asi::ASI_PST8_PRIMARY_LITTLE:
	    case Sf_Asi::ASI_PST8_SECONDARY:
	    case Sf_Asi::ASI_PST8_SECONDARY_LITTLE:
	    case Sf_Asi::ASI_PST16_PRIMARY:
	    case Sf_Asi::ASI_PST16_PRIMARY_LITTLE:
	    case Sf_Asi::ASI_PST16_SECONDARY:
	    case Sf_Asi::ASI_PST16_SECONDARY_LITTLE:
	    case Sf_Asi::ASI_PST32_PRIMARY:
	    case Sf_Asi::ASI_PST32_PRIMARY_LITTLE:
	    case Sf_Asi::ASI_PST32_SECONDARY:
	    case Sf_Asi::ASI_PST32_SECONDARY_LITTLE:
	    {
		readUnsignedMemory( readXact, 1 );
		RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
		break;
	    }

	    default:
	    {
		RIESLING_THROW_DOMAIN_ERROR( string("Unimplemented load float asi = ").
		       append( StringUtils::uint642HexString( asi ) ));
		break;
	    }
	}

    } else if (op3 == T3o3_ldfa) {
	MemoryTransaction readXact( addr, asi, iw, MemoryTransaction::READ, getStrand() );

	memValue = readUnsignedMemory( readXact, 4 );
        // checkTrapBeforeCommit(iw);
	freg_->setSpfp( rd, NumericUtils::getLoWord( memValue ) );
    } else {
	if ((addr & 0x7) == 0x4) {
	    uint_t trapType  = Sf_Trap::LDDF_mem_address_not_aligned;
	    uint_t faultType = 0;
	    //Ni pass the correct asi instead of default ??
	    MemoryTransaction xact( addr, asi, iw, MemoryTransaction::READ, getStrand() );
	    xact.size( iw.getInstAlignSize() );
	    mmu_->dMmuTrap( xact, trapType, faultType, NULL );
	}

	MemoryTransaction readXact( addr, asi, iw, MemoryTransaction::READ, getStrand() );
	memValue = readUnsignedMemory( readXact, 8 );
        // checkTrapBeforeCommit(iw);
	freg_->setDpfp( rd, memValue );
    }

    setFpDirtyBits( rd );  // Dirty bits are set pessimistically before fp_disabled trap
}

//
// LOAD FLOAT (4, 8 bytes) regular (non ASI) operation
//
void InstructionEmulator::exec_LDF ( InstructionWord &iw, VaddrT addr )
{
    uint32_t op3 = iw.op3();
    uint32_t rd  = iw.rd();

    if( op3 == T3o3_lddf ){
	rd = InstructionWord::decodeDoubleReg( rd );
    }

    if ( !fpuEnabled() ){
	if ( setFpDirtyBitsWhenFpDisabled() ) {
	    // checkTrapBeforeCommit(iw);
	    setFpDirtyBits( rd );                    // Dirty bits are set pessimistically before fp_disabled trap
	}
	RIESLING_TRAP( Sf_Trap::fp_disabled );
    } 									

    if (op3 == T3o3_ldf) {
	// checkTrapBeforeCommit(iw);
	freg_->setSpfp( rd, readUnsigned( addr, 4, iw ) );
    } else {

	if ((addr & 0x7) == 0x4) {
	    uint_t trapType  = Sf_Trap::LDDF_mem_address_not_aligned;
	    uint_t faultType = 0;
	    MemoryTransaction xact( addr, getDefaultDataAsi(), iw, MemoryTransaction::READ, getStrand() );
	    xact.size( iw.getInstAlignSize() );
	    mmu_->dMmuTrap( xact, trapType, faultType, NULL );
	}

	// checkTrapBeforeCommit(iw);
	freg_->setDpfp( rd, readUnsigned( addr, 8, iw ) );
    }

    setFpDirtyBits( rd );
}

//
// STORE FLOAT (4, 8 bytes)  ASI operation
//
void InstructionEmulator::exec_STF_ASI ( InstructionWord &iw, VaddrT addr )
{
    uint64_t   memValue = 0;
    uint64_t   regValue = 0;
    uint64_t   mask   = 0;
    uint32_t op3 = iw.op3();
    uint32_t rd  = iw.rd();
    AsiT asi = iw.i() ? asi_->getNative() : iw.immAsi();

    if( op3 == T3o3_stdfa ){
	rd = InstructionWord::decodeDoubleReg( rd );
    } 

    if ( !fpuEnabled() ){
	RIESLING_TRAP( Sf_Trap::fp_disabled );
    } 									

    if( isXlateAsi( asi ) ){
	if( getAsiInstance()->isBlockOp( asi ) ){
	    // block load asi
	    handleBlockOp( iw, addr, asi, MemoryTransaction::WRITE, rd );
	} else if( getAsiInstance()->isFLdSt( asi ) ){

	    switch (asi) {
		case Sf_Asi::ASI_PST8_PRIMARY:
		case Sf_Asi::ASI_PST8_PRIMARY_LITTLE:
		case Sf_Asi::ASI_PST8_SECONDARY:
		case Sf_Asi::ASI_PST8_SECONDARY_LITTLE:
		case Sf_Asi::ASI_PST16_PRIMARY:
		case Sf_Asi::ASI_PST16_PRIMARY_LITTLE:
		case Sf_Asi::ASI_PST16_SECONDARY:
		case Sf_Asi::ASI_PST16_SECONDARY_LITTLE:
		case Sf_Asi::ASI_PST32_PRIMARY:
		case Sf_Asi::ASI_PST32_PRIMARY_LITTLE:
		case Sf_Asi::ASI_PST32_SECONDARY:
		case Sf_Asi::ASI_PST32_SECONDARY_LITTLE:
		    if ( op3 == T3o3_stdfa ) {
			addr = ireg_->get(iw.rs1());
		    }
		    if ( iw.getOpcode() == InstructionWord::STDFA ) {
			if ( iw.i() == 1 ) {
			    //TODO  move to InstructionWord checking
			    RIESLING_TRAP( Sf_Trap::illegal_instruction );
			}
		    }
		    break;
		default:
		    break;
	    }


	    MemoryTransaction writeXact( addr, asi, iw, MemoryTransaction::WRITE, getStrand() );

	    switch (asi) {
		case Sf_Asi::ASI_FL8_PRIMARY:
		case Sf_Asi::ASI_FL8_SECONDARY:
		case Sf_Asi::ASI_FL8_PRIMARY_LITTLE:
		case Sf_Asi::ASI_FL8_SECONDARY_LITTLE:
		{
		    regValue = freg_->getDpfp( rd ) & 0x00FF;
		    writeXact.setData( regValue );
		    // checkTrapBeforeCommit(iw);
		    write( writeXact, 1 );
		    break;
		}
		case Sf_Asi::ASI_FL16_PRIMARY:
		case Sf_Asi::ASI_FL16_SECONDARY:
		case Sf_Asi::ASI_FL16_PRIMARY_LITTLE:
		case Sf_Asi::ASI_FL16_SECONDARY_LITTLE:
		{
		    regValue = freg_->getDpfp( rd ) & 0x00FFFF;
		    writeXact.setData( regValue );
		    // checkTrapBeforeCommit(iw);
		    write( writeXact, 2 );
		    break;
		}
		case Sf_Asi::ASI_PST8_PRIMARY:
		case Sf_Asi::ASI_PST8_PRIMARY_LITTLE:
		case Sf_Asi::ASI_PST8_SECONDARY:
		case Sf_Asi::ASI_PST8_SECONDARY_LITTLE:
		{
		    MemoryTransaction readXact( addr, asi, iw, MemoryTransaction::READ, getStrand() );

		    memValue = readUnsignedMemory( readXact, 8 );

		    uint32_t rs2 = ireg_->get( iw.rs2() );

		    mask = 0;
		    for (int index=0; index<8; index++) {
			if (rs2 & 0x1)
			    mask |= (0x000000FFULL << (index * 8));
			rs2 >>= 1;
		    }

		    memValue &= ~mask;

		    regValue = freg_->getDpfp( rd );
		    regValue &= mask;

		    memValue |= regValue;

		    writeXact.setData( memValue );
		    // checkTrapBeforeCommit(iw);
		    write( writeXact, 8 );
		    break;
		}
		case Sf_Asi::ASI_PST16_PRIMARY:
		case Sf_Asi::ASI_PST16_PRIMARY_LITTLE:
		case Sf_Asi::ASI_PST16_SECONDARY:
		case Sf_Asi::ASI_PST16_SECONDARY_LITTLE:
		{
		    MemoryTransaction readXact( addr, asi, iw, MemoryTransaction::READ, getStrand() );

		    memValue = readUnsignedMemory( readXact, 8 );

		    uint32_t rs2 = ireg_->get( iw.rs2() );

		    mask = 0;
		    for (int index=0; index<4; index++) {
			if (rs2 & 0x1)
			    mask |= (0x0000FFFFULL << (index * 16));
			rs2 >>= 1;
		    }

		    memValue &= ~mask;

		    regValue = freg_->getDpfp( rd );
		    regValue &= mask;

		    memValue |= regValue;

		    writeXact.setData( memValue );
		    // checkTrapBeforeCommit(iw);
		    write( writeXact, 8 );
		    break;
		}
		case Sf_Asi::ASI_PST32_PRIMARY:
		case Sf_Asi::ASI_PST32_PRIMARY_LITTLE:
		case Sf_Asi::ASI_PST32_SECONDARY:
		case Sf_Asi::ASI_PST32_SECONDARY_LITTLE:
		{
		    MemoryTransaction readXact( addr, asi, iw, MemoryTransaction::READ, getStrand() );

		    memValue = readUnsignedMemory( readXact, 8 );

		    uint32_t rs2 = ireg_->get( iw.rs2() );

		    mask = 0;
		    for (int index=0; index<2; index++) {
			if (rs2 & 0x1)
			    mask |= (0x00FFFFFFFFULL << (index * 32));
			rs2 >>= 1;
		    }

		    memValue &= ~mask;

		    regValue = freg_->getDpfp( rd );
		    regValue &= mask;

		    memValue |= regValue;

		    writeXact.setData( memValue );
		    // checkTrapBeforeCommit(iw);
		    write( writeXact, 8 );
		    break;
		}
		default:
		{
		    RIESLING_THROW_DOMAIN_ERROR( string("Unimplemented partial store asi = ").
			   append( StringUtils::uint642HexString( asi ) ));
		}
	    }
	} else if (op3 == T3o3_stfa) {
	    MemoryTransaction writeXact( addr, asi, iw, MemoryTransaction::WRITE, getStrand() );

	    regValue = freg_->getSpfp( rd );
	    writeXact.setData( NumericUtils::getLoWord( regValue ) );
	    // checkTrapBeforeCommit(iw);
	    write( writeXact, 4 );
	} else {

	    if ((addr & 0x7) == 0x4) {
		uint_t trapType  = Sf_Trap::STDF_mem_address_not_aligned;
		uint_t faultType = 0;
		//Ni pass the correct asi instead of default ??
		//MemoryTransaction xact( addr, getDefaultDataAsi(), iw, MemoryTransaction::WRITE, getStrand() );
		MemoryTransaction xact( addr, asi, iw, MemoryTransaction::WRITE, getStrand() );
		xact.size( iw.getInstAlignSize() );
		mmu_->dMmuTrap( xact, trapType, faultType, NULL );
	    }

	    MemoryTransaction writeXact( addr, asi, iw, MemoryTransaction::WRITE, getStrand() );

	    regValue = freg_->getDpfp( rd );
	    writeXact.setData( regValue );
	    // checkTrapBeforeCommit(iw);
	    write( writeXact, 8 );
	} 
    } else {
	uint64_t data = 0;
	if( op3 == T3o3_stdfa ){
	    data = freg_->getDpfp( rd ); 
	} else {
	    data = NumericUtils::getLoWord( freg_->getSpfp( rd ) ); 
	}
        // checkTrapBeforeCommit(iw);
	asiDispWrite( asi, addr, data, iw );
	return;
    }

}

//
// STORE FLOAT (4, 8 bytes) regular (non ASI) operation
//
void InstructionEmulator::exec_STF ( InstructionWord &iw, VaddrT addr )
{
    uint32_t op3 = iw.op3();
    uint32_t rd  = iw.rd();

    if( op3 == T3o3_stdf ){
	rd = InstructionWord::decodeDoubleReg( rd );
    }

    if ( !fpuEnabled() ){
	RIESLING_TRAP( Sf_Trap::fp_disabled );
    } 									

    if (op3 == T3o3_stf) {
        // checkTrapBeforeCommit(iw);
	write( addr, 4, iw, freg_->getSpfp( rd ) );
    } else {

	if ((addr & 0x7) == 0x4) {
	    uint_t trapType  = Sf_Trap::STDF_mem_address_not_aligned;
	    uint_t faultType = 0;
	    MemoryTransaction xact( addr, getDefaultDataAsi(), iw, MemoryTransaction::WRITE, getStrand() );
	    xact.size( iw.getInstAlignSize() );
	    mmu_->dMmuTrap( xact, trapType, faultType, NULL );
	}

        // checkTrapBeforeCommit(iw);
	write( addr, 8, iw, freg_->getDpfp( rd ) );
    }
}

void InstructionEmulator::exec_stqf( InstructionWord &iw )
{
//     RIESLING_TRAP( Sf_Trap::illegal_instruction );
}


void InstructionEmulator::exec_prefetch( InstructionWord &iw )
{
    prefetchHelper( iw, getDefaultDataAsi() );
}

void InstructionEmulator::exec_ldqfa( InstructionWord &iw )
{
//     RIESLING_TRAP( Sf_Trap::illegal_instruction );
}

void InstructionEmulator::exec_stqfa( InstructionWord &iw )
{
//     RIESLING_TRAP( Sf_Trap::illegal_instruction );
}

void InstructionEmulator::exec_prefetcha( InstructionWord &iw )
{
    prefetchHelper( iw, iw.i() ? asi_->getNative() : iw.immAsi() );
}

void InstructionEmulator::prefetchHelper( InstructionWord &iw, AsiT asi )
{
    uint64_t ea = (GET_IU_EA( iw )) & ~0x03ULL;
    uint32_t fcn = ((iw.getNative() >> 25) & 0x1f);

//     if ((fcn >= 0x5) && (fcn <= 15)) {
// 	RIESLING_TRAP( Sf_Trap::illegal_instruction );
//     }

    // checkTrapBeforeCommit(iw);

    // Impl Dep #103(5)
    // fcn = 16..31 is treated as a NOP unless these 
    // values are available for an implementation to use
    // if( fcn < 5 ){
    {
	try {
	    if( isXlateAsi( asi ) ){
		MemoryTransaction readXact( ea, asi, iw, MemoryTransaction::READ, getStrand() );
		readXact.size( 64 );
		PaddrT paddr = translate( readXact );
		if (BlazeCBInterface::getblazeprefetchcb()) {
		  (*BlazeCBInterface::getblazeprefetchcb())(getStrand()->getId(), ea, paddr, fcn);
		}
	    } else {
		asiDispRead( asi, ea, iw );
		if (BlazeCBInterface::getblazeprefetchcb()) {
		  (*BlazeCBInterface::getblazeprefetchcb())(getStrand()->getId(), ea, ea, fcn);
		}
	    }
	} catch ( BasicTrap &t ) {
	    // do nothing.  prefetches don't cause traps

	    // Impl Dep #117 whether an prefetch always succeeds when 
	    //  the MMU is disabled is impl dep
	    // Impl Dep #103(1) Whether the execution of a prefech instruction has
	    //  observalble effects in privileged mode is implmentation dependent.
	    // Impl Dep #103(2) Whether the execution of a prefetch instr can cause
	    //  a data_access_mmu_miss is implementation dependent. 
	}
    }
}

/////////////////////////////////////////////////////////////

//
// Load unsigned word operation
// cpu.RD <- (unsigned)[addr]
// 
//
void InstructionEmulator::exec_LDUW( InstructionWord &iw, VaddrT addr )
{
    // TODO this behavior needs be made configurable
//     if( iw.i() == 0 && NumericUtils::getBits( iw.getNative(), 12, 5 ) != 0 ){
// 	RIESLING_TRAP( Sf_Trap::illegal_instruction );
//     }

    uint32_t rd = iw.rd();
    uint64_t memValue;

    memValue = readUnsigned( addr, 4, iw );
    // checkTrapBeforeCommit(iw);
    if ( rd != 0 ) {
	ireg_->set( rd, NumericUtils::getLoWord( memValue ) );
    }
}

//
// Load unsigned byte operation
// cpu.RD <- (unsigned byte)[addr]
//
void InstructionEmulator::exec_LDUB( InstructionWord &iw, VaddrT addr )
{
    // TODO this behavior needs be made configurable
//     if( iw.i() == 0 && NumericUtils::getBits( iw.getNative(), 12, 5 ) != 0 ){
// 	RIESLING_TRAP( Sf_Trap::illegal_instruction );
//     }

    uint64_t   memValue;
    int   rd = iw.rd();


    memValue = readUnsigned( addr, 1, iw );
    // checkTrapBeforeCommit(iw);
    if (rd != 0) {
	ireg_->set( rd, memValue );
    }
}

//
// Load unsigned half word operation
// cpu.RD <- (unsigned hword)[addr]
//
void InstructionEmulator::exec_LDUH( InstructionWord &iw, VaddrT addr )
{
    // TODO this behavior needs be made configurable
//     if( iw.i() == 0 && NumericUtils::getBits( iw.getNative(), 12, 5 ) != 0 ){
// 	RIESLING_TRAP( Sf_Trap::illegal_instruction );
//     }

    uint64_t   memValue;
    int   rd = iw.rd();

    memValue = readUnsigned( addr, 2, iw );
    // checkTrapBeforeCommit(iw);
    if (rd != 0) {
	ireg_->set( rd, memValue );
    }
}


//
// Load SIGNED operation
// cpu.RD <- (signed)[addr]
//
void InstructionEmulator::exec_LOAD_SIGNED( InstructionWord &iw, VaddrT addr )
{
    // TODO this behavior needs be made configurable
//     if( iw.i() == 0 && NumericUtils::getBits( iw.getNative(), 12, 5 ) != 0 ){
// 	RIESLING_TRAP( Sf_Trap::illegal_instruction );
//     }

    uint_t size;
    uint_t op3 = iw.op3();
    uint64_t regValue;
    int rd = iw.rd();

    if        (op3 == T3o3_ldsw){
	size = 4;
    } else if (op3 == T3o3_ldsb){
	size = 1;
    } else if (op3 == T3o3_ldsh){
	size = 2;
    } else {
	// should NEVER reach here
	RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
    }

    regValue = readSigned( addr, size, iw );
    // checkTrapBeforeCommit(iw);
    if ( rd != 0 ) {
	ireg_->set( rd, regValue );
    }
}


/// TODO : revise all LD/ST operations (IO LD/ST)

//
// Load double word operation
// cpu.RD <- [addr]
//
void InstructionEmulator::exec_LDX( InstructionWord &iw, VaddrT addr )
{
    // TODO this behavior needs be made configurable
//     if( iw.i() == 0 && NumericUtils::getBits( iw.getNative(), 12, 5 ) != 0 ){
// 	RIESLING_TRAP( Sf_Trap::illegal_instruction );
//     }

    uint64_t   memValue;
    int   rd = iw.rd();

    memValue = readUnsigned( addr, 8, iw );
    // checkTrapBeforeCommit(iw);
    if (rd != 0) {
	ireg_->set( rd, memValue );
    }
}

//
// Store  byte/hword/word/dword operation
// cpu.RD -> [addr]
//
void InstructionEmulator::exec_STORE( InstructionWord &iw, VaddrT addr )
{
    // TODO this behavior needs be made configurable
//     if( iw.i() == 0 && NumericUtils::getBits( iw.getNative(), 12, 5 ) != 0 ){
// 	RIESLING_TRAP( Sf_Trap::illegal_instruction );
//     }

    uint32_t rd  = iw.rd();
    uint32_t op3 = iw.op3();

    // checkTrapBeforeCommit(iw);

    if        (op3 == T3o3_stw) {
	write( addr, 4,  iw, ireg_->get( rd ) );
    } else if (op3 == T3o3_stx) {
	write( addr, 8,  iw, ireg_->get( rd ) );
    } else if (op3 == T3o3_stb) {
	write( addr, 1,  iw, ireg_->get( rd ) );
    } else if (op3 == T3o3_sth) {
	write( addr, 2,  iw, ireg_->get( rd ) );
    } else {
	// we should NEVER get here.
	RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
    }
}

////////////////////////////////////////////////////
//
// CASXA (ASI = 0x80)
//
//  Requires LOCKING in case of MP-ON_MP
//
void InstructionEmulator::exec_CASXA_80( InstructionWord &i, VaddrT addr )
{
    RIESLING_THROW_DOMAIN_ERROR( "Uimplemented instruction" );
#if 0

	uint32_t context;
	uint64_t paddr;
	uint64_t tmp;
	uint64_t tmprd_l;
	int      err;
	uint32_t rd = X_RD(iw);
	uint32_t rs2 = X_RS2(iw);

        // context = cpup->dmmu->pcontext.s.context;
	HI_W(addr) &= cpup->pstate_am_hi_mask;
	if ((err = dmmu_check_LDX(addr)) > 0) {
	    handle_dmmu_err(cpup, addr, 1, err, iw);
	    return;
	}
	paddr = translate_va_pa_store_atomic(cpup, addr, 0x80);
	if (paddr == BADADDR)
	    return;
	if (is_addrIO(paddr)) {
	    // CAS operation is invalid within IO address space
	    TRAP_exec(cpup, T_DATA_AEXC);
	    return;
	}
        /// TODO : check it
	tmp = cpup->current_reg[rd];
	mem_lock(mm1, paddr);
	tmprd_l = memread64u(mm1, paddr);
	if (cpup->current_reg[rs2] == tmprd_l) {
	    memwrite64u_nl (mm1, paddr, tmp);
	}

TRACEMOD_LDST (cpup, addr, paddr);

	mem_unlock(mm1, paddr);
	cpup->current_reg[rd] = tmprd_l;
#endif
}

////////////////////////////////////////////////////
//
//  Requires LOCKING in case of MP-ON-MP
//
void InstructionEmulator::exec_LDSTUB( InstructionWord &iw, VaddrT vaddr )
{

    uint32_t op3 = iw.op3();
    uint32_t rd = iw.rd();

    uint32_t asi;
    uint64_t memValue;
    
    if (op3 == T3o3_ldstuba) {
	asi = iw.i() ? asi_->getNative() : iw.immAsi();
    } else {
        asi = getDefaultDataAsi();
    }


    if( isXlateAsi( asi ) ){

	MemoryTransaction readXact( vaddr, asi, iw, MemoryTransaction::READ|MemoryTransaction::LOCK, getStrand() );
        readXact.atomic(true);

	memValue = readUnsignedMemory( readXact, 1 ) & 0x00FF;
	// checkTrapBeforeCommit(iw);
	if (rd != 0) {
	    ireg_->set( rd, memValue );
	}

	MemoryTransaction writeXact( vaddr, asi, iw, MemoryTransaction::WRITE|MemoryTransaction::UNLOCK, getStrand() );
        writeXact.atomic(true);
	writeXact.setData( 0x00FF );
	write( writeXact, 1 );

    } else {

	memValue = asiDispRead( asi, vaddr, iw ) & 0x00FF;
	// checkTrapBeforeCommit(iw);
	if (rd != 0) {
	    ireg_->set( rd, memValue );
	}

	// TODO asiDispWrite writes to 8 bytes instead of 1 byte

	asiDispWrite( asi, vaddr, 0x00FF, iw ) ;
    }
}


/////////////////////////////////////////////////

void InstructionEmulator::do_special_st( uint32_t reg, uint8_t asi, uint64_t addr)
{
    RIESLING_THROW_DOMAIN_ERROR( "Uimplemented instruction" );
#if 0
	int i;
	switch (asi) {
	case e_ASI_FL8_PRIMARY:
	case e_ASI_FL8_SECONDARY:
		{
		    uint8_t *loc = (uint8_t *) & sp->fpu_regfile.dregs[reg];
		    memwrite8u(mm1, addr, *(loc + BYTE_OFFST));
		}
		break;

	case e_ASI_FL16_PRIMARY:
	case e_ASI_FL16_SECONDARY:
		{
		    HWord *loc = (HWord *) & sp->fpu_regfile.dregs[reg];
		    memwrite16u(mm1, addr, *(loc + BYTE_OFFST));
		}
		break;

	case e_ASI_BLOCK_PRIMARY:
	case e_ASI_BLOCK_SECONDARY:
	case e_ASI_BLOCK_AS_IF_USER_PRIMARY:
	case e_ASI_BLOCK_AS_IF_USER_SECONDARY:
	case e_ASI_COMMIT_PRIMARY:
	case e_ASI_COMMIT_SECONDARY:
		{
		    uint8_t *loc = (uint8_t *) & sp->fpu_regfile.dregs[reg];

		    for (i = 0; i < 8; i++) {
		        memwrite64u(mm1, addr + (i << 3), *(uint64_t *) (loc + (i << 3)));
		    }
		    return;
		}
	}
#endif
}

/////////////////////////////////////////////////
//
// The routine below implements very special
// case of so called CONDITIONAL PARTIAL STORE.
// Ordinarily this operation (STFA (ASI = 0xc0 ...))
// is used together with EDGE8(16, 32) VIS instruction.
// RS2 of PST is used ad a MASK applied to stored double word
// and doesn't participate in EA computation
//
void InstructionEmulator::do_pst( InstructionWord& iw, uint32_t rd, uint8_t asi, uint64_t addr)
{
    RIESLING_THROW_DOMAIN_ERROR( "Uimplemented instruction" );
#if 0
	uint64_t rs1;
	uint64_t rs2;
	int i, j;

	GET_R1_R2(iw, rs1, rs2);
	switch (asi) {
	case e_ASI_PST8_PRIMARY:
	case e_ASI_PST8_SECONDARY:
		{
		    /* Eight conditional byte stores from rd */
		    uint8_t *byte_num = (uint8_t*)& sp->fpu_regfile.dregs[rd];
		  
		    for (i = 7, j = 0; i >= 0; i--, j++) {
		        if (rs2 & (1 << i)) {
			    memwrite8u(mm1, addr + j, byte_num[j]);
			} 
		    }
		}
		break;

	case e_ASI_PST16_PRIMARY:
	case e_ASI_PST16_SECONDARY:
		{
		    /* Four conditional halfword stores from rd */
		    uint16_t *hword_num = (uint16_t*)& sp->fpu_regfile.dregs[rd];

		    for (i = 3, j = 0; i >= 0; i--, j++) {
		        if (rs2 & (1 << i)) {
			    memwrite16u(mm1, addr + (j << 1), hword_num[j]);
			}
		    }
		}
		break;

	case e_ASI_PST32_PRIMARY:
	case e_ASI_PST32_SECONDARY:
		{
		    /* Two conditional word stores from rd */
		    uint32_t *word_num = (uint32_t*)& sp->fpu_regfile.dregs[rd];

		    if (rs2 & 0x2) {
		        /* Store HIGH uint32_t into memory */
		        memwrite32u(mm1, addr, word_num[0]);
		    }
		    if (rs2 & 0x1) {
		        /* Store Low word to memory + 4 */
		        memwrite32u(mm1, addr + 4, word_num[1]);
		    }
		}
		break;
	default:
		fprintf(stderr,	"Internal Error !! Unknown ASI 0x%x (STORE-pst) %d\n",asi);
		return;
	}
#endif
}


/////////////////////////////////////////////////
//
//  Requires LOCKING in case of MP-ON_MP
//
void InstructionEmulator::exec_swap( uint32_t asi, uint64_t vaddr, uint32_t rd, InstructionWord &iw)
{
    uint64_t rdValue = ireg_->get( rd );
    uint64_t value;

    if( isXlateAsi( asi ) ){

	MemoryTransaction readXact( vaddr, asi, iw, MemoryTransaction::READ|MemoryTransaction::LOCK, getStrand() );
	readXact.atomic( true );

	value = readUnsignedMemory( readXact, 4 );
	// checkTrapBeforeCommit(iw);
	if ( rd != 0 ) {
	    ireg_->set( rd, NumericUtils::getLoWord( value ) );
	}

	MemoryTransaction writeXact( vaddr, asi, iw, MemoryTransaction::WRITE|MemoryTransaction::UNLOCK, getStrand() );
	writeXact.atomic( true );
	writeXact.setData( NumericUtils::getLoWord( rdValue ) );
	write( writeXact, 4 );

    } else {
	value = asiDispRead( asi, vaddr, iw );
	// checkTrapBeforeCommit(iw);
	if ( rd != 0 ) {
	    ireg_->set( rd, NumericUtils::getLoWord( value ) );
	}
	asiDispWrite( asi, vaddr, NumericUtils::getLoWord( rdValue ), iw );
    }
}

/////////////////////////////////////////////////
//
//  Requires LOCKING in case of MP-ON_MP
//

void InstructionEmulator::exec_cas ( InstructionWord & iw)
{
    uint64_t memValue;

    uint32_t op3 = iw.op3();
    uint32_t rd  = iw.rd();

    uint32_t asi = iw.i() ? asi_->getNative() : iw.immAsi();

    uint64_t vaddr    = ireg_->get(iw.rs1());
    uint64_t rs2Value = ireg_->get(iw.rs2());
    uint64_t rdValue  = ireg_->get(rd );

    if( isXlateAsi( asi ) ){

        if (op3 == T3o3_casa) {

	    MemoryTransaction readXact( vaddr, asi, iw, MemoryTransaction::READ|MemoryTransaction::LOCK, getStrand() );
	    readXact.atomic( true );
	    memValue = NumericUtils::getLoWord( readUnsignedMemory( readXact, 4 ) );
	    // checkTrapBeforeCommit(iw);
	    if ( rd != 0 ) {
		ireg_->set( rd, memValue );
	    }

	    if (memValue == NumericUtils::getLoWord( rs2Value )) {

		MemoryTransaction writeXact( vaddr, asi, iw, MemoryTransaction::WRITE|MemoryTransaction::UNLOCK, getStrand() );
		writeXact.atomic( true );
		writeXact.setData( NumericUtils::getLoWord( rdValue ) );
		write( writeXact, 4 );
	    } else {
	        readXact.access( MemoryTransaction::READ|MemoryTransaction::UNLOCK|MemoryTransaction::NOSYNC );
		addressSpace_->access ( readXact );
	    }

	} else {

	    MemoryTransaction readXact( vaddr, asi, iw, MemoryTransaction::READ|MemoryTransaction::LOCK, getStrand() );
	    readXact.atomic( true );
	    memValue = readUnsignedMemory( readXact, 8 );
	    // checkTrapBeforeCommit(iw);
	    if ( rd != 0 ) {
		ireg_->set( rd, memValue );
	    }

	    if (memValue == rs2Value) {

		MemoryTransaction writeXact( vaddr, asi, iw, MemoryTransaction::WRITE|MemoryTransaction::UNLOCK, getStrand() );
		writeXact.atomic( true );
		writeXact.setData( rdValue );
		write( writeXact, 8 );
	    } else {
	        readXact.access( MemoryTransaction::READ|MemoryTransaction::UNLOCK|MemoryTransaction::NOSYNC );
		addressSpace_->access ( readXact );
	    }

	}

    } else {

        if (op3 == T3o3_casa) {

	    memValue = NumericUtils::getLoWord( asiDispRead( asi, vaddr, iw ) );
	    // checkTrapBeforeCommit(iw);
	    if ( rd != 0 ) {
		ireg_->set( rd, memValue );
	    }
	    if (memValue ==  NumericUtils::getLoWord( rs2Value ) ) {
		// TODO asiDispWrite writes to 8 bytes instead of 4 bytes
		asiDispWrite( asi, vaddr, NumericUtils::getLoWord( rdValue ), iw );
	    }

	} else {

	    memValue = asiDispRead( asi, vaddr, iw );
	    // checkTrapBeforeCommit(iw);
	    if ( rd != 0 ) {
		ireg_->set( rd, memValue );
	    }
	    if (memValue == rs2Value) {
		asiDispWrite( asi, vaddr, rdValue, iw );
	    }
	}
    }
}

/////////////////////////////////////////////////

void InstructionEmulator::setFpDirtyBits( uint_t decodedFreg )
{
    if( decodedFreg < 32 ){
	fprs_->setDL( 1 );
    } else {
	fprs_->setDU( 1 );
    }
}

/////////////////////////////////////////////////


bool InstructionEmulator::fpuEnabled()
{
    return pstate_->getPEF() && fprs_->getFEF();
}

/////////////////////////////////////////////////

void InstructionEmulator::handleBlockOp( InstructionWord &iw, 
				    VaddrT addr, 
				    AsiT asi,  
				    MemoryTransaction::AccessT access,
				    uint_t rd )
{
    // register must be aligned on an 8 double-precision register boundary

    if( ( iw.getOpcode() == InstructionWord::LDDFA ) || (iw.getOpcode() == InstructionWord::STDFA) ){
#ifdef RS_MPSAS_COMPATIBLE
	//TODO  move to InstructionWord checking
        if( (asi == 0xE0) || (asi == 0xE1) ){
	    if( (rd & ~0x01) != rd ){
		RIESLING_TRAP( Sf_Trap::illegal_instruction );	
	    }
	} else {
	    if( (rd & ~0x0F) != rd ){
		RIESLING_TRAP( Sf_Trap::illegal_instruction );	
	    }
	}
#else /* RS_MPSAS_COMPATIBLE */
	if( (rd & ~0x0F) != rd ){
	    RIESLING_TRAP( Sf_Trap::illegal_instruction );	
	}
#endif /* RS_MPSAS_COMPATIBLE */
    }

    if ( !fpuEnabled() ){
	if ( setFpDirtyBitsWhenFpDisabled() ) {
	    setFpDirtyBits( rd );  // Dirty bits are set pessimistically before fp_disabled trap
	}
	RIESLING_TRAP( Sf_Trap::fp_disabled );
    } 									

    MemoryTransaction blockXact( addr, asi, iw, access, getStrand() );
    blockXact.size( 64 );
    mmu_->handleData( blockXact );
    PaddrT paddr = blockXact.paddr();
    // checkTrapBeforeCommit(iw);
    if( blockXact.readXact() ){
	addressSpace_->access( blockXact );
	uint_t dwIdx = 0;
	for( uint_t reg = rd; reg < rd + 16; reg += 2, ++dwIdx ){
	    freg_->setDpfp( reg, blockXact.getData( dwIdx ) );
	}
    } else if( blockXact.writeXact() ){
	uint_t dwIdx = 0;
	for( uint_t reg = rd; reg < rd + 16; reg += 2, ++dwIdx ){
	    blockXact.setData( dwIdx, freg_->getDpfp( reg ) );
	}
	addressSpace_->access( blockXact );
    } else {
	RS_DOMAIN_ERR( "Internal error, unknown access type." );
    }
}

